﻿using System;
using BlockLogic.Impl.Blocks.Checker.Enum;
using BlockLogic.Interface;
using ActionLogic.Interface;
using ActionLogic.Impl;
using BlockLogic.Interface.Blocks.Checker;
using BlockLogic.Interface.Blocks.Checker.Strategy;
using System.Collections.Generic;
using System.Linq;
using BlockLogic.Impl.Enum;

namespace BlockLogic.Impl.Blocks.Checker
{
    public class CheckerBlock : Block, ICheckerBlock
    {
        private const int RECALCULATION_COUNT = 50;

        private int _curCommonCount;

        public IRequestBuffer InputBuffer { get; private set; }
        public ICheckerStrategy Strategy { get; set; }
        public Dictionary<CheckerParameter, object> ReturnParameters { get; private set; }

        public CheckerBlock(Guid id, BlockType type)
            : base(id, type)
        {
            InputBuffer = new RequestBuffer(ID, 10000);
            ReturnParameters = new Dictionary<CheckerParameter, object>();
        }

        public override void Initialize()
        {
            _curCommonCount = 0;
            ReturnParameters.Clear();
            InputBuffer.Clear();
            InputBuffer.OnRequestAdded += CheckBufferSize;
            ReturnParameters[CheckerParameter.STATE] = "NO_DATA";
        }

        private List<double> GetData()
        {
            var initTimeList = new List<double>();
            {
                initTimeList.AddRange(InputBuffer.GetAllRequest().Select(r => r.InitTime + r.ServiceTime + r.WaitingTime));
            }
            initTimeList.Sort();

            var betweenTimeList = new List<double>();
            for (int i = 0; i < initTimeList.Count - 1; i++)
            {
                betweenTimeList.Add(initTimeList[i + 1] - initTimeList[i]);
            }

            return betweenTimeList;
        }

        private void CheckBufferSize()
        {
            _curCommonCount++;

            if (_curCommonCount > InputBuffer.MaxCapacity)
            {
                InputBuffer.OnRequestAdded -= CheckBufferSize;
                ReturnParameters[CheckerParameter.STATE] = "HAVE_CHECKED";
                return;
            }

            if (0 == _curCommonCount % RECALCULATION_COUNT)
            {
                IActionExecutor executor = ActionExecutor.GetInstance();
                executor.Add(0, this.Check);
            }
        }

        public void Check()
        {
            Strategy.Data = GetData();
        
            ReturnParameters[CheckerParameter.DEGREES_OF_FREEDOM] = Strategy.DegreesOfFreedom();
            ReturnParameters[CheckerParameter.PEARSON_CRITERION] = Strategy.PearsonCriterion();
            ReturnParameters[CheckerParameter.POINTS] = Strategy.LinearHistogram();
            ReturnParameters[CheckerParameter.THEORETICAL_POINTS] = Strategy.TheoreticalHistogram();
            ReturnParameters[CheckerParameter.COUNT] = _curCommonCount;
            ReturnParameters[CheckerParameter.STATE] = "CHECKING";
        }
    }
}
